home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / emac16ds.zip / EMACSPWN.ASM < prev    next >
Assembly Source File  |  1991-04-02  |  22KB  |  1,142 lines

  1. ;
  2. ;    --- Version 2.3 90-10-11 21:26 ---
  3. ;
  4. ;    SPAWN.ASM - Main function for memory swapping spawn call.
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic GmbH
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ;    PASCAL:
  14. ;        function do_spawn (method: byte; 
  15. ;                   swapfname, execfname, cmdtail: string; 
  16. ;                   envlen: word; var envp)
  17. ;    C:
  18. ;        int do_spawn (unsigned char method, 
  19. ;                  char *swapfname, char *execfname, char *cmdtail,
  20. ;                      unsigned envlen, char *envp)
  21. ;
  22. ;    Assemble with
  23. ;
  24. ;    tasm  /DPASCAL spawn          - Turbo Pascal (Tasm only), near
  25. ;    tasm  /DPASCAL /DFARCALL spawn    - Turbo Pascal (Tasm only), far
  26. ;    ?asm  spawn;              - C, default model (small)
  27. ;    ?asm  /DMODL=large spawn      - C, large model
  28. ;    
  29. ;    NOTE:    For C, change the 'model' directive below according to your
  30. ;        memory model, or define MODL=xxx on the command line.
  31. ;
  32. ;    The 'method' parameter determines the swap/spawn/exec
  33. ;    function:
  34. ;        00 = Spawn, don't swap
  35. ;        01 = Spawn, swap
  36. ;        80 = Exec, don't swap
  37. ;
  38. ;    If swapping (01), the following flags can be ORed into 'method':
  39. ;
  40. ;        02 = Use EMS if possible
  41. ;        04 = Use 'create temporary file' call (swapfname is path only)
  42. ;
  43. ;
  44. ;    For 'cmdtail' and 'execfname', the first byte must contain 
  45. ;    the length of the string, even when calling from C.
  46. ;
  47. ;    'swapfname' and 'execfname' must be zero terminated, even when
  48. ;    calling from Pascal.
  49. ;
  50. ;    NOTE: 'swapfname' usage also expects first byte=length  --jbt
  51.  
  52.  
  53.  
  54.     IFDEF    PASCAL
  55.     .model    tpascal
  56. ;
  57. ptrsize    =    1
  58.     ELSE
  59.     IFNDEF    MODL
  60.     .model    small,c
  61.     ELSE
  62. %    .model    MODL,c
  63.     ENDIF
  64. ;
  65. ptrsize    =    @DataSize
  66.     ENDIF
  67. ;
  68. stacklen    =    160        ; 80 word local stack
  69. ;
  70. blocksize    =    16 * 1024    ; Write block size
  71. blocksize_paras    =    blocksize / 16
  72. blockshift    =    10        ; shift factor for paragraphs
  73. blockmask    =    blocksize_paras - 1    ; Write block mask
  74. ;
  75. ; Method flags
  76. ;
  77. SWAPPING    =    01h
  78. USE_EMS        =    02h
  79. CREAT_TEMP    =    04h
  80. TERMINATE    =    80h
  81. ;
  82. EMM_INT        =    67h
  83. ;
  84. exec_block    struc
  85. envseg    dw    ?
  86. ppar    dw    ?
  87. pparseg    dw    ?
  88. fcb1    dw    ?
  89. fcb1seg    dw    ?
  90. fcb2    dw    ?
  91. fcb2seg    dw    ?
  92. exec_block    ends
  93. ;
  94. mcb        struc
  95. id        db    ?
  96. owner        dw    ?
  97. paras        dw    ?
  98.         db    3 dup(?)
  99. mcb_reserved    db    ?
  100. mcb        ends
  101. ;
  102. next_mcbs    struc
  103. next_addr    dw    ?
  104. next_size    dw    ?
  105. next_blocks    dw    ?
  106. next_rest    dw    ?
  107. next_mcbs    ends
  108. ;
  109. ;----------------------------------------------------------------------
  110. ;
  111. ;    The memory structure for the shrunk-down code
  112. ;
  113. parseg    struc
  114. parbeg    db    5ch dup(?)        ; start after PSP
  115. ;
  116. page_frame    dw    ?        ; EMS page frame (0 if no EMS)
  117. memsize        dw    ?        ; total paragraphs
  118. rd_blocks    dw    ?        ; number of blocks in swapfile
  119. rd_rest        dw    ?        ; number of bytes in last block
  120. save_ss        dw    ?        ; saved global ss
  121. save_sp        dw    ?        ; saved global sp
  122. spx        dw    ?        ; saved local sp
  123. next_mcb    db    TYPE next_mcbs dup(?)
  124. expar        db    TYPE exec_block dup (?) ; exec-parameter-block
  125. zero        dw    ?        ; Zero command tail length (dummy)
  126. method        db    ?        ; method parameter
  127. handle        dw    ?        ; swap file or EMS handle (0 for EXEC)
  128. tempfilename    db    81 dup(?)    ; swap file name
  129. ;
  130. parseg    ends
  131. ;
  132.  
  133.     assume    cs:code, ds:data
  134.  
  135.  
  136. data    segment    byte public
  137. ;    .data
  138.     IFDEF    PASCAL
  139.     extrn    prefixseg: word
  140.     ELSE
  141.     extrn    _psp: word
  142.     ENDIF
  143. ;
  144. ;
  145.  
  146. data    ends
  147. code    segment    byte public
  148. ;    .code
  149.  
  150. ;
  151. ;       This part of the program code will be moved to address
  152. ;    'codeloc' and executed there.
  153. ;
  154. ;    Registers on entry:
  155. ;        BX    = paragraphs to keep
  156. ;        CX     = length of environment to copy or zero
  157. ;        DS:SI    = environment source
  158. ;        ES:DI    = environment destination
  159. ;        (ES = our low core code segment)
  160. ;
  161. doexec:
  162.     jcxz    noenvcpy
  163.     rep movsb
  164. noenvcpy:
  165.     push    es            ; DS = ES = low core
  166.     pop    ds
  167.     cmp    ds:handle,0
  168.     je    no_shrink
  169.         mov    ah,04ah
  170.     int     21h                     ; free memory
  171.     mov    bx,ds:next_mcb.next_addr
  172. ;
  173. free_loop:
  174.     or    bx,bx
  175.     jz    no_shrink
  176.     mov    es,bx
  177.     mov    bx,es:mcb_reserved.next_addr
  178.     mov    ax,es
  179.     inc    ax
  180.     mov    es,ax
  181.     mov    ah,049h
  182.     int    21h
  183.     jmp    free_loop
  184. ;
  185. no_shrink:
  186.     push    ds
  187.     pop    es
  188.     mov    dx,filename        ; params for exec
  189.     mov    bx,expar
  190.     mov    ax,04b00h
  191.     int    21h            ; exec
  192. ;
  193.     mov    bx,cs
  194.     mov    ds,bx
  195.     mov    es,bx
  196.     mov    ss,bx
  197.     mov    sp,ds:spx
  198.     cld
  199.     push    ax
  200.     pushf
  201. ;
  202.     test    ds:method,TERMINATE    ; exec?
  203.     jz    exec_ckswap
  204.     jmp    exec_term        ; terminate if yes
  205. ;
  206. exec_ckswap:
  207.     test    ds:method,SWAPPING    ; swap?
  208.     jnz    exec_noterm        ; go swap back in if yes
  209.     jmp    exec_retn        ; return if spawn and no swap
  210. ;
  211. exec_noterm:
  212.     mov    ah,4ah            ; expand memory
  213.     mov    bx,ds:memsize
  214.     int    21h
  215.     jnc    exec_memok
  216.     jmp    exec_term        ; terminate if error
  217. ;
  218. ;    Swap memory back
  219. ;
  220. exec_memok:
  221.     cmp    ds:page_frame,0
  222.     jne    exec_swems
  223.     jmp    exec_swfile        ; go swap from file if not EMS
  224. ;
  225. ;    Swap in memory from EMS
  226. ;
  227. exec_swems:
  228.     mov    ax,cs
  229.     dec    ax
  230.     push    ax            ; push current MCB
  231.     push    ds            ; push data segment
  232.     mov    ax,next_mcb
  233.     push    ax            ; and next MCB pointer
  234.     mov    dx,ds:handle
  235.     mov    cx,ds:rd_blocks
  236.     push    ds:rd_rest        ; push bytes in last block
  237.     mov    ds,ds:page_frame
  238.     xor    bx,bx
  239.     mov    di,swapbeg
  240. ;
  241. swap_in_ems:
  242. ;
  243.     jcxz    swin_ems_rest
  244. ;
  245. swin_ems:
  246.     push    cx
  247.     mov    ax,4400h
  248.     int    EMM_INT
  249.     or    ah,ah
  250.     jnz    exec_term
  251.     mov    cx,blocksize
  252.     mov    si,0
  253.     push    di
  254.     rep movsb
  255.     pop    di
  256.     mov    ax,es
  257.     add    ax,blocksize_paras
  258.     mov    es,ax
  259.     pop    cx
  260.     inc    bx
  261.     loop    swin_ems
  262. ;
  263. swin_ems_rest:
  264.     pop    cx
  265.     jcxz    swin_ems_rdy
  266.     mov    ax,4400h
  267.     int    EMM_INT
  268.     or    ah,ah
  269.     jnz    exec_term
  270.     mov    si,0
  271.     rep movsb
  272.     inc    bx
  273. ;
  274. swin_ems_rdy:
  275.     pop    si            ; next offset
  276.     pop    ds            ; segment
  277.     pop    es            ; current MCB
  278.     mov    ax,[si].next_addr
  279.     or    ax,ax
  280.     jz    swin_ems_complete
  281.     push    ax            ; next MCB
  282.     push    ax            ; also is data segment for next struc
  283.     mov    cx,mcb_reserved
  284.     push    cx            ; next offset
  285.     mov    ax,[si].next_rest
  286.     push    ax            ; bytes in last block
  287. ;
  288.     push    bx
  289.     push    dx
  290.     call    get_mcb            ; alloc MCB, ES = dest segment
  291.     pop    dx
  292.     pop    bx
  293.     mov    cx,[si].next_blocks    ; number of blocks
  294.     mov    ds,cs:page_frame    ; reload page frame addr
  295.     mov    di,0
  296.     jmp    swap_in_ems
  297. ;
  298. swin_ems_complete:
  299.     mov    ah,45h
  300.     int    EMM_INT
  301.     mov    ax,cs
  302.     mov    es,ax
  303.     mov    ds,ax
  304.     jmp    exec_retn
  305. ;
  306. exec_term:
  307.     cmp    cs:page_frame,0
  308.     je    eterm_noems
  309.     mov    dx,cs:handle
  310.     mov    ah,45h
  311.     int    EMM_INT
  312. eterm_noems:
  313.     mov    ax,4c00h                ; terminate process
  314.         int     21h
  315. ;
  316. ;    Swap in memory from file
  317. ;
  318. exec_swfile:
  319.     mov    ax,cs
  320.     dec    ax
  321.     push    ax            ; push current MCB
  322.     push    ds            ; push data segment
  323.     mov    ax,next_mcb
  324.     push    ax            ; and next MCB pointer
  325.     push    ds:rd_rest        ; push bytes in last block
  326. ;
  327.     mov    dx,tempfilename
  328.     mov    ax,3d92h        ; open exclusive, R/W
  329.     int    21h
  330.     jc    exec_term        ; abort if file not found
  331.     mov    ds:handle,ax
  332.     mov    bx,ax
  333. ;
  334.     mov    cx,blocksize
  335.     mov    dx,swapbeg
  336.     mov    si,ds:rd_blocks
  337. ;
  338. exec_rdblocks:
  339.     mov    ah,3fh            ; read file
  340.     cmp    si,0
  341.     je    exec_rdr
  342.     dec    si
  343.     int    21h
  344.     jc    exec_term        ; terminate if error reading
  345.     mov    ax,ds
  346.     add    ax,blocksize_paras
  347.     mov    ds,ax
  348.     jmp    exec_rdblocks
  349. ;
  350. exec_rdr:
  351.     pop    cx            ; bytes in last block
  352.     jcxz    exec_norest
  353.     int    21h
  354.     jc    exec_term        ; terminate if error reading
  355. ;
  356. exec_norest:
  357.     pop    si            ; next offset
  358.     pop    ds            ; segment
  359.     pop    es            ; current MCB
  360.     mov    ax,[si].next_addr
  361.     or    ax,ax
  362.     jz    swin_file_complete
  363.     push    ax            ; next MCB
  364.     push    ax            ; also is data segment for next struc
  365.     mov    cx,mcb_reserved
  366.     push    cx            ; next offset
  367.     mov    ax,[si].next_rest
  368.     push    ax            ; bytes in last block
  369. ;
  370.     push    bx
  371.     call    get_mcb            ; alloc MCB, ES = dest segment
  372.     pop    bx
  373.     mov    si,[si].next_blocks    ; number of blocks
  374.     mov    ax,es
  375.     mov    ds,ax
  376.     mov    cx,blocksize
  377.     mov    dx,0
  378.     jmp    exec_rdblocks
  379. ;
  380. swin_file_complete:
  381.     mov    ah,3eh
  382.     int    21h            ; close file
  383.     mov    ax,cs
  384.     mov    ds,ax
  385.     mov    es,ax
  386. ;
  387. exec_retn:
  388.     popf
  389.     pop    ax
  390.     jc    exec_fault        ; return EXEC error code if fault
  391.     mov    ah,4dh            ; else get program return code
  392.     int    21h
  393. ;    ret    far            ; can't use a RET here since
  394.     db    0cbh            ; we are using .model
  395. ;
  396. exec_fault:
  397.     mov    ah,3            ; return error as 03xx
  398. ;    ret    far
  399.     db    0cbh
  400. ;
  401. ;
  402. ;    get_mcb allocates a block of memory by modifying the MCB chain
  403. ;    directly.
  404. ;
  405. ;    On entry, DS:SI points to the next_mcbs descriptor for the block,
  406. ;          ES:0  is the MCB for the current block.
  407. ;
  408. ;    On exit,  ES is the wanted MCB.
  409. ;
  410. ;    Uses     AX, BX, CX
  411. ;
  412. get_mcb    proc    near
  413. ;     
  414.     cmp    es:id,4dh        ; 4d means normal MCB
  415.     jnz    gmcb_abort        ; halt if no next
  416.     mov    ax,es            ; current MCB
  417.     add    ax,es:paras
  418.     inc    ax
  419.     mov    es,ax            ; next MCB
  420.     cmp    ax,[si].next_addr
  421.     ja    gmcb_abort        ; halt if next MCB > wanted
  422.     je    mcb_found        ; jump if same addr as wanted
  423.     add    ax,es:paras        ; last addr
  424.     cmp    ax,[si].next_addr
  425.     jb    get_mcb            ; loop if last < wanted
  426.     cmp    es:owner,0
  427.     jne    gmcb_abort        ; halt if not free
  428. ;
  429. ;    The wanted MCB starts within the current MCB. We now have to
  430. ;    create a new MCB at the wanted position, which is initially
  431. ;    free, and shorten the current MCB to reflect the reduced size.
  432. ;
  433.     mov    bx,es            ; current
  434.     inc    bx            ; + 1 (header doesn't count)
  435.     mov    ax,[si].next_addr
  436.     sub    ax,bx            ; paragraphs between MCB and wanted
  437.     mov    bx,es:paras        ; paras in current MCB
  438.     sub    bx,ax            ; remaining paras
  439.     dec    bx            ; -1 for header
  440.     mov    es:paras,ax        ; set new size for current
  441.     mov    cl,es:id        ; old id
  442.     mov    es:id,4dh        ; set id: there is a next
  443.     mov    ax,[si].next_addr    ; now point to new MCB
  444.     mov    es,ax
  445.     mov    es:id,cl        ; and init to free
  446.     mov    es:owner,0
  447.     mov    es:paras,bx
  448. ;
  449. ;    We have found an MCB at the right address. If it's not free,
  450. ;    abort. Else check the size. If the size is ok, we're done 
  451. ;    (more or less).
  452. ;
  453. mcb_found:
  454.     mov    es,ax
  455.     cmp    es:owner,0
  456.     je    mcb_check        ; continue if free
  457. ;
  458. gmcb_abort:
  459.     jmp    exec_term
  460. ;
  461. mcb_check:
  462.     mov    ax,es:paras        ; size
  463.     cmp    ax,[si].next_size    ; size needed
  464.     jae    mcb_ok            ; ok if enough space
  465. ;
  466. ;    If there's not enough room in this MCB, check if the next
  467. ;    MCB is free, too. If so, coalesce both MCB's and check again.
  468. ;
  469.     cmp    es:id,4dh
  470.     jnz    gmcb_abort        ; halt if no next
  471.     push    es            ; save current
  472.     mov    bx,es
  473.     add    ax,bx
  474.     inc    ax            ; next MCB
  475.     mov    es,ax
  476.     cmp    es:owner,0        ; next free ?
  477.     jne    gmcb_abort        ; halt if not
  478.     mov    ax,es:paras        ; else load size
  479.     inc    ax            ; + 1 for header
  480.     mov    cl,es:id        ; and load ID
  481.     pop    es            ; back to last MCB
  482.     add    es:paras,ax        ; increase size
  483.     mov    es:id,cl        ; and store ID
  484.     jmp    mcb_check        ; now try again
  485. ;
  486. ;    The MCB is free and large enough. If it's larger than the
  487. ;    wanted size, create another MCB after the wanted.
  488. ;
  489. mcb_ok:
  490.     mov    bx,es:paras
  491.     sub    bx,[si].next_size
  492.     jz    mcb_no_next        ; ok, no next to create
  493.     push    es
  494.     dec    bx            ; size of next block
  495.     mov    ax,es
  496.     add    ax,[si].next_size
  497.     inc    ax            ; next MCB addr
  498.     mov    cl,es:id        ; id of this block
  499.     mov    es,ax            ; address next
  500.     mov    es:id,cl        ; store id
  501.     mov    es:paras,bx        ; store size
  502.     mov    es:owner,0        ; and mark as free
  503.     pop    es            ; back to old MCB
  504.     mov    es:id,4dh        ; mark next block present
  505.     mov    ax,[si].next_size    ; and set size to wanted
  506.     mov    es:paras,ax
  507. ;
  508. mcb_no_next:
  509.     mov    es:owner,cx        ; set owner to current PSP
  510.     ret                ; all finished (whew!)
  511. ;
  512. get_mcb    endp
  513. ;
  514. ireti:
  515.     iret
  516. ;
  517. iretoff    =    offset ireti - offset doexec
  518. ;
  519. execlen    =    $-doexec
  520.  
  521.  
  522. code    ends
  523.  
  524. ;
  525. ;--------------------------------------------------------------------
  526. ;
  527. parseg2    struc
  528.         db    TYPE parseg dup(?)
  529. ;
  530. codeloc        db    execlen dup(?)    ; code
  531. ;    
  532. div0_off    dw    ?        ; divide by zero vector save
  533. div0_seg    dw    ?
  534. xfcb1        db    16 dup(?)    ; default FCB
  535. xfcb2        db    16 dup(?)    ; default FCB
  536. filename    db    82 dup(?)    ; exec filename
  537. progpars    db    128 dup(?)    ; command tail
  538.         db    stacklen dup(?)    ; stack space
  539. ;
  540. parseg2    ends
  541. ;
  542. mystack        equ    progpars+128+stacklen
  543. parend        equ    mystack
  544. ;
  545. reslen    = (parend - parbeg)
  546. ;
  547. keep_paras    = (reslen + 15) shr 4    ; paragraphs to keep
  548. swapbeg        = keep_paras shl 4    ; start of swap space
  549. savespace    = swapbeg - 5ch        ; length of overwritten area
  550. ;
  551. ;    Space for saving the part of the memory image below the
  552. ;    swap area that is overwritten by our code.
  553. ;
  554.  
  555. data    segment    byte public
  556. ;    .data
  557.  
  558. save_dat    db    savespace dup(?)
  559. ;       
  560.  
  561. data    ends
  562. code    segment    byte public
  563. ;    .code
  564.  
  565. ;
  566. emm_name    db    'EMMXXXX0'
  567. ;
  568.     IFDEF    PASCAL
  569.     IFDEF    FARCALL
  570. do_spawn    PROC    far pmethod: byte, swapfname: dword, execfname: dword, params: dword, envlen: word, envp: dword
  571.     ELSE
  572. do_spawn    PROC    near pmethod: byte, swapfname: dword, execfname: dword, params: dword, envlen: word, envp: dword
  573.     ENDIF
  574.     ELSE
  575. do_spawn    PROC    uses si di,pmethod:byte,swapfname:ptr byte,execfname:ptr byte,params:ptr byte,envlen:word,envp:ptr byte
  576.     ENDIF
  577. ;
  578.     public    do_spawn
  579. ;
  580.     push    ds
  581.     mov    ax,ds
  582.     mov    es,ax
  583.     cld
  584. ;
  585.     IFDEF    PASCAL
  586.     mov    ax,prefixseg
  587.     ELSE
  588.     mov    ax,_psp
  589.     ENDIF
  590.     mov    ds,ax            ; DS points to PSP
  591. ;
  592. ;    Check if spawn is too low in memory
  593. ;
  594.     mov    bx,cs
  595.     mov    dx,offset doexec
  596.     mov    cl,4
  597.     shr    dx,cl
  598.     add    bx,dx            ; normalized start of this code
  599.     mov    dx,keep_paras        ; the end of the modified area
  600.     add    dx,ax            ; plus PSP = end paragraph
  601.     cmp    bx,dx
  602.     ja    save_mem    ; ok if start of code > end of low mem
  603.     pop    ds
  604.     mov    ax,500h
  605.     ret
  606. ;
  607. ;    Save the memory below the swap space
  608. ;
  609. save_mem:
  610.     mov    si,5ch
  611.     mov    di,offset save_dat
  612.     mov    cx,savespace
  613.     rep movsb
  614. ;
  615.     mov    es,ax            ; ES points to PSP
  616.     dec    ax
  617.     mov    ds,ax            ; DS now points to MEM CTL
  618.     mov    bx,word ptr ds:3    ; allocated paragraphs
  619.     mov    es:memsize,bx
  620. ;
  621. ;    Now walk the chain of memory blocks, chaining all blocks
  622. ;    belonging to this process. Four unused words in the MCB are
  623. ;    used to store the paragraph address and size of the next block.
  624. ;
  625.     push    es
  626.     mov    bx,ds:owner        ; the current process
  627.     mov    di,next_mcb
  628. ;
  629. mcb_chain:
  630.     cmp    ds:id,4dh        ; normal block?
  631.     jne    mcb_ready        ; ready if end
  632.     mov    cx,ds
  633.     add    cx,ds:paras        ; start + length
  634.     inc    cx            ; next MCB
  635.     mov    ds,cx
  636.     cmp    bx,ds:owner        ; our process?
  637.     jne    mcb_chain        ; loop if not
  638.     mov    es:[di].next_addr,ds
  639.     mov    ax,ds:paras
  640.     mov    es:[di].next_size,ax
  641.     inc    ax
  642.     push    ax
  643.     mov    cl,blockshift
  644.     shr    ax,cl            ; number of blocks
  645.     mov    es:[di].next_blocks,ax
  646.     pop    ax
  647.     and    ax,blockmask
  648.     mov    cl,4
  649.     shl    ax,cl            ; convert to no. of bytes
  650.     mov    es:[di].next_rest,ax
  651.     mov    ax,ds
  652.     mov    es,ax
  653.     mov    di,mcb_reserved
  654.     jmp    mcb_chain
  655. ;
  656. mcb_ready:
  657.     mov    es:[di].next_addr,0
  658.     pop    es
  659. ;
  660.     mov    es:page_frame,0
  661. ;
  662. ;    Swap out memory
  663. ;
  664.     mov    al,pmethod
  665.     mov    es:method,al
  666.     test    al,SWAPPING
  667.     jnz    do_swap
  668.     jmp    no_swap
  669. ;
  670. do_swap:
  671.     mov    bx,es:memsize
  672.     sub    bx,keep_paras        ; minus resident paragraphs
  673.     mov    ax,bx
  674.     mov    cl,blockshift
  675.     shr    ax,cl            ; number of blocks in swapfile
  676.     mov    es:rd_blocks,ax
  677.     xchg    ax,bx
  678.     and    ax,blockmask
  679.     mov    cl,4
  680.     shl    ax,cl            ; number of bytes in last block
  681.     mov    es:rd_rest,ax
  682. ;
  683. ;    Check for EMS swap
  684. ;
  685.     test    pmethod,USE_EMS
  686.     jnz    try_ems
  687.     jmp    no_ems
  688. ;
  689. try_ems:
  690.     or    ax,ax
  691.     jz    no_rest
  692.     inc    bx            ; number of EMS blocks needed
  693. ;
  694. ;    For EMS, we have to determine the total number of blocks
  695. ;    for all memory blocks.
  696. ;
  697. no_rest:
  698.     mov    si,next_mcb
  699.     push    es
  700.     pop    ds
  701. ;
  702. tot_blocks:
  703.     mov    cx,[si].next_addr
  704.     or    cx,cx
  705.     jz    tot_ready
  706.     add    bx,[si].next_blocks
  707.     mov    ax,[si].next_rest
  708.     mov    ds,cx
  709.     mov    si,mcb_reserved
  710.     or    ax,ax
  711.     jz    tot_blocks
  712.     inc    bx
  713.     jmp    tot_blocks
  714. ;
  715. tot_ready:
  716.     push    bx
  717.     push    es
  718.     mov    al,EMM_INT
  719.     mov    ah,35h
  720.     int    21h            ; get EMM int vector
  721.     mov    ax,cs
  722.     mov    ds,ax
  723.     mov    si,offset emm_name
  724.     mov    di,10
  725.     mov    cx,8
  726.     repz cmpsb
  727.     pop    es
  728.     pop    bx
  729.     jz    ems_ok_1
  730.     jmp    no_ems
  731. ;
  732. ems_ok_1:
  733.     mov    ah,40h
  734.     int    EMM_INT
  735.     or    ah,ah
  736.     jz    ems_ok_2
  737.     jmp    no_ems
  738. ;
  739. ems_ok_2:
  740.     mov    ah,46h
  741.     int    EMM_INT
  742.     or    ah,ah
  743.     jz    ems_ok_3
  744.     jmp    no_ems
  745. ;
  746. ems_ok_3:
  747.     cmp    al,30h
  748.     jae    ems_ok_4
  749.     jmp    no_ems
  750. ;
  751. ems_ok_4:
  752.     push    bx
  753.     mov    ah,41h
  754.     int    EMM_INT
  755.     mov    es:page_frame,bx
  756.     pop    bx
  757.     or    ah,ah
  758.     jz    ems_ok_5
  759.     jmp    no_ems
  760. ;
  761. ;    EMS present, try to allocate pages
  762. ;
  763. ems_ok_5:
  764.     mov    ah,43h
  765.     int    EMM_INT
  766.     or    ah,ah
  767.     jz    ems_ok_6
  768.     jmp    no_ems
  769. ;
  770. ;    EMS pages allocated, swap to EMS
  771. ;
  772. ems_ok_6:
  773.     mov    es:handle,dx
  774.     push    es
  775.     mov    ax,es
  776.     mov    ds,ax
  777.     push    ds
  778.     mov    ax,next_mcb
  779.     push    ax
  780.     push    es:rd_rest
  781.     mov    cx,es:rd_blocks
  782.     mov    es,es:page_frame
  783.     xor    bx,bx
  784.     mov    si,swapbeg
  785. ;
  786. swap_ems:
  787.     jcxz    swapout_erest        ; jump if no full blocks
  788. ;
  789. swapout_ems:
  790.     push    cx
  791.     mov    ax,4400h            ; map page, phys = 0
  792.     int    EMM_INT
  793.     or    ah,ah
  794.     jnz    ems_error
  795.     mov    cx,blocksize
  796.     mov    di,0
  797.     push    si
  798.     rep movsb
  799.     pop    si
  800.     mov    ax,ds
  801.     add    ax,blocksize_paras
  802.     mov    ds,ax
  803.     pop    cx
  804.     inc    bx
  805.     loop    swapout_ems
  806. ;
  807. swapout_erest:
  808.     pop    cx            ; remaining bytes
  809.     push    cx
  810.     push    cx
  811.     jcxz    swapout_erdy
  812.     mov    ax,4400h        ; map page, phys = 0
  813.     int    EMM_INT
  814.     or    ah,ah
  815.     jnz    ems_error
  816.     mov    di,0
  817.     rep movsb
  818.     inc    bx
  819. ;
  820. swapout_erdy:
  821.     add    sp,4
  822.     pop    si            ; next offset
  823.     pop    ds            ; segment
  824. ;
  825.     mov    ax,[si].next_addr
  826.     or    ax,ax
  827.     jz    ems_complete
  828.     push    ax
  829.     mov    cx,mcb_reserved
  830.     push    cx
  831.     mov    cx,[si].next_blocks
  832.     mov    si,[si].next_rest
  833.     push    si
  834.     mov    si,0
  835.     mov    ds,ax
  836.     jmp    swap_ems
  837. ;
  838. ems_complete:
  839.     pop    es
  840.     jmp    no_swap
  841. ;
  842. ems_error:
  843.     add    sp,8
  844.     pop    es
  845.     mov    ah,45h            ; release EMS pages on error
  846.     int    EMM_INT
  847. ;
  848. ;    No or not enough EMS storage, swap to file
  849. ;
  850. no_ems:
  851.     mov    es:page_frame,0
  852.     IF    ptrsize
  853.     lds    dx,swapfname
  854.     ELSE
  855.     pop    ds
  856.     push    ds
  857.     mov    dx,swapfname
  858.     ENDIF
  859.     inc    dx
  860.     mov    cx,2            ; hidden
  861.     mov    ah,3ch            ; create file
  862.     test    pmethod,CREAT_TEMP
  863.     jz    no_temp
  864.     mov    ah,5ah
  865. ;
  866. no_temp:
  867.     int    21h
  868.     jc    spawn_error
  869.     mov    es:handle,ax
  870.     mov    bx,ax
  871. ;
  872. ;    save the file name in the base area
  873. ;
  874.     mov    di,tempfilename
  875.     mov    cx,81
  876.     mov    si,dx
  877.     rep movsb
  878. ;
  879.     mov    ax,es
  880.     mov    ds,ax
  881.     push    ds
  882.     mov    si,next_mcb
  883.     mov    cx,es:rd_blocks
  884.     mov    di,es:rd_rest
  885.     mov    dx,swapbeg
  886. ;
  887. swap_file:
  888.     jcxz    swout_rest
  889. ;
  890. swout_blocks:
  891.     push    cx
  892.     mov    cx,blocksize
  893.     mov    ah,40h
  894.     int    21h
  895.     pop    cx
  896.     jc    spawn_error
  897.     mov    ax,ds
  898.     add    ax,blocksize_paras
  899.     mov    ds,ax
  900.     loop    swout_blocks
  901. ;
  902. swout_rest:
  903.     mov    cx,di
  904.     jcxz    swap_ready
  905.     mov    ah,40h
  906.     int    21h
  907.     jnc    swap_ready
  908. ;
  909. spawn_error:
  910.     add    sp,2
  911.     pop    ds
  912.     mov    ax,100h
  913.     ret
  914. ;
  915. swap_ready:
  916.     pop    ds
  917.     mov    ax,[si].next_addr
  918.     or    ax,ax
  919.     jz    swap_complete
  920.     mov    cx,[si].next_blocks
  921.     mov    di,[si].next_rest
  922.     mov    dx,0
  923.     mov    si,mcb_reserved
  924.     mov    ds,ax
  925.     push    ds
  926.     jmp    swap_file
  927. ;
  928. ;    Swapout complete
  929. ;
  930. swap_complete:
  931.     mov    ah,3eh
  932.     int    21h            ; close file
  933. ;
  934. no_swap:
  935. ;
  936. ;    Prepare exec parameter block
  937. ;
  938.     mov    ax,es
  939.     mov    es:expar.fcb1seg,ax
  940.     mov    es:expar.fcb2seg,ax
  941.     mov    es:expar.pparseg,ax
  942.     mov    es:expar.envseg,0
  943. ;
  944. ;    The 'zero' word is located at 80h in the PSP, the start of
  945. ;    the command line. So as not to confuse MCB walking programs,
  946. ;    a command line length of zero is inserted here.
  947. ;
  948.     mov    es:zero,0d00h        ; 00h,0dh = empty command line
  949. ;
  950. ;    Init default fcb's by parsing parameter string
  951. ;
  952.     IF    ptrsize
  953.     lds    si,params
  954.     ELSE
  955.     pop    ds
  956.     push    ds
  957.     mov    si,params
  958.     ENDIF
  959.     push    si
  960.     mov    di,xfcb1
  961.     mov    es:expar.fcb1,di
  962.     push    di
  963.     mov    cx,16
  964.     xor    ax,ax
  965.     rep stosw            ; init both fcb's to 0
  966.     pop    di
  967.     mov    ax,2901h
  968.     IFDEF    PASCAL
  969.     inc    si
  970.     ENDIF
  971.     int    21h
  972.     mov    di,xfcb2
  973.     mov    es:expar.fcb2,di
  974.     mov    ax,2901h
  975.     int    21h
  976.     pop    si
  977. ;
  978. ;    move command tail string into low core
  979. ;
  980.     mov    cl,byte ptr [si]
  981.     xor    ch,ch
  982.     mov    di,progpars
  983.     mov    es:expar.ppar,di
  984.     inc    cx
  985.     rep movsb
  986.     mov    al,0dh
  987.     stosb
  988. ;
  989. ;    move filename string into low core
  990. ;
  991.     IF    ptrsize
  992.     lds    si,execfname
  993.     ELSE
  994.     mov    si,execfname
  995.     ENDIF
  996.     lodsb
  997.     mov    cl,al
  998.     xor    ch,ch
  999.     mov    di,filename
  1000.     rep movsb
  1001.     xor    al,al
  1002.     stosb
  1003. ;
  1004. ;    Setup environment copy
  1005. ;
  1006.     mov    bx,keep_paras        ; paras to keep
  1007.     mov    cx,envlen        ; environment size
  1008.     jcxz    no_environ        ; go jump if no environment
  1009.     mov    ax,cx            ; convert envsize to paras
  1010.     add    ax,15
  1011.     shr    ax,1
  1012.     shr    ax,1
  1013.     shr    ax,1
  1014.     shr    ax,1
  1015.     add    bx,ax            ; add envsize to paras to keep
  1016.     IF    ptrsize
  1017.     lds    si,envp
  1018.     ELSE
  1019.     mov    si,envp
  1020.     ENDIF
  1021. ;
  1022.     mov    ax,es            ; low core segment
  1023.     add    ax,keep_paras        ; plus fixed paras
  1024.     mov    es:expar.envseg,ax    ; = new environment segment
  1025. ;
  1026. ;    Save stack regs, switch to local stack
  1027. ;
  1028. no_environ:
  1029.     mov    es:save_ss,ss
  1030.     mov    es:save_sp,sp
  1031.     mov    ax,es
  1032.     mov    ss,ax
  1033.     mov    sp,mystack
  1034. ;
  1035.     push    cx
  1036.     push    si
  1037.     push    ds
  1038. ;
  1039. ;    Move code into low core
  1040. ;
  1041.     mov    di,codeloc
  1042.     call    near ptr nextloc        ; where are we ?
  1043. nextloc:
  1044.     pop    si            ; si = abs. addr of 'nextloc'
  1045.     push    si
  1046.         add     si,doexec-nextloc
  1047.         mov     cx,execlen
  1048.     push    cs
  1049.     pop    ds
  1050.         rep movsb                       ; move down code
  1051. ;
  1052. ;    save and patch INT0 (division by zero) vector
  1053. ;
  1054.     xor    ax,ax
  1055.     mov    ds,ax
  1056.     mov    ax,word ptr ds:0
  1057.     mov    es:div0_off,ax
  1058.     mov    ax,word ptr ds:2
  1059.     mov    es:div0_seg,ax
  1060.     mov    word ptr ds:0,codeloc + iretoff
  1061.     mov    word ptr ds:2,es
  1062. ;
  1063. ;    Push return address on local stack
  1064. ;
  1065.     pop    ax
  1066.     add    ax,exec_cont-nextloc
  1067. ;
  1068.     pop    ds            ; pop environment segment
  1069.     pop    si            ; pop environment offset
  1070.     pop    cx            ; pop environment length
  1071.     mov    di,swapbeg        ; pop environment destination
  1072. ;
  1073.     push    cs            ; push return segment
  1074.     push    ax            ; push return offset
  1075.     mov    es:spx,sp        ; save stack pointer
  1076. ;
  1077. ;    Goto low core code
  1078. ;
  1079.     push    es            ; push entry segment
  1080.         mov    ax,codeloc
  1081.         push    ax            ; push entry offset
  1082. ;    ret    far            ; can't use RET here because
  1083.     db    0cbh            ; of .model
  1084. ;
  1085. ;----------------------------------------------------------------
  1086. ;
  1087. ;    low core code will return to this location
  1088. ;
  1089. exec_cont:
  1090.     mov    ss,es:save_ss        ; reload stack
  1091.     mov    sp,es:save_sp
  1092. ;
  1093. ;    restore INT0 (division by zero) vector
  1094. ;
  1095.     xor    cx,cx
  1096.     mov    ds,cx
  1097.     mov    cx,es:div0_off
  1098.     mov    word ptr ds:0,cx
  1099.     mov    cx,es:div0_seg
  1100.     mov    word ptr ds:2,cx
  1101. ;
  1102.     pop    ds
  1103. ;
  1104.     mov    bx,es:page_frame    ; save EMS status in BX
  1105. ;
  1106. ;    Restore overwritten part of program
  1107. ;
  1108.     mov    si,offset save_dat
  1109.     mov    di,5ch
  1110.     mov    cx,savespace
  1111.     rep movsb
  1112. ;
  1113.     or    bx,bx            ; EMS swap?
  1114.     jnz    exec_finish        ; ready if yes
  1115. ;
  1116.     push    ds            ; else delete swapfile
  1117.     push    ax
  1118.     IF    ptrsize
  1119.     lds    dx,swapfname
  1120.     ELSE
  1121.     mov    dx,swapfname
  1122.     ENDIF
  1123.     inc    dx
  1124. ;
  1125.     mov    ah,41h
  1126.     int    21h            ; delete file
  1127.     pop    ax
  1128.     pop    ds
  1129. ;
  1130. exec_finish:
  1131.     ret
  1132. ;    
  1133. do_spawn    ENDP
  1134. ;
  1135.  
  1136. code    ends
  1137.  
  1138.  
  1139.         END
  1140.  
  1141.  
  1142.